import json
import time
from selenium import webdriver
from selenium.webdriver import Proxy
from selenium.webdriver.common.proxy import ProxyType
from seleniumwire import webdriver as webdriver_
import requests


class craw_X:
    def __init__(self, *args, **kwargs):
        self.proxies = {
            "http": "http://127.0.0.1:7890",
            "https": "http://127.0.0.1:7890",
        }
        self.screen_name = kwargs.get('screen_name')
        self.tag = kwargs.get('tag')
        self.cookies = dict()
        self.headers = dict()
        self.twi_username = kwargs.get('twi_username')
        self.twi_password = kwargs.get('twi_password')
        self.twi_name = kwargs.get('twi_name')
        self.chrome_binary_path = kwargs.get('chrome_binary_path')
        self.chrome_driver_path = kwargs.get('chrome_driver_path')
        self.driver = None

    def run(self):
        chrome_options = webdriver.ChromeOptions()
        chrome_options.add_argument('--proxy-server={}'.format(self.proxies['http']))
        chrome_options.binary_location = self.chrome_binary_path
        self.driver = webdriver.Chrome(executable_path=self.chrome_driver_path, chrome_options=chrome_options)

        # self.cookies = {
        #     'ct0': 'e2ac2893dc528f0651dafa70c524da3238a1dd4915df1c6b273b77f0be489d4bd31614e5e1b5e3911c62ac95cbadc90959f534eeffb61bd9c7955e07de2aa04d83600e4807be19f633bc218ce6e96aff',
        #     'auth_token': '7ef4ebec205719a99accab4be67dc3f91537d7cc'
        # }
        # self.headers = {
        #     'Authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
        #     'x-csrf-token': 'e2ac2893dc528f0651dafa70c524da3238a1dd4915df1c6b273b77f0be489d4bd31614e5e1b5e3911c62ac95cbadc90959f534eeffb61bd9c7955e07de2aa04d83600e4807be19f633bc218ce6e96aff'
        #
        # }

        self.selenium_log()
        for name in self.screen_name:
            id_ = self.get_id(name)
            result, info = self.get_content(id_, 3)
            with open(f'./output/result_{name}.json', 'w') as file:
                file.write(json.dumps(result))
            with open(f'./output/info_{name}.json', 'w') as file:
                file.write(json.dumps(info))

            fing = self.get_Following(id_)
            with open(f'./output/fing_{name}.json', 'w') as file:
                file.write(json.dumps(fing))

            fer = self.get_Followers(id_)
            with open(f'./output/fer_{name}.json', 'w') as file:
                file.write(json.dumps(fer))

        for tag in self.tag:

            tweet = self.tweet_for_tag(tag)
            with open(f'./output/tweet_{tag}.json', 'w') as file:
                file.write(json.dumps(tweet))

            user = self.user_for_tag(tag)
            with open(f'./output/user_{tag}.json', 'w') as file:
                file.write(json.dumps(user))

        # self.selenium_logout()

    def selenium_logout(self):
        ...

    def selenium_log(self):

        self.driver.get('https://twitter.com/i/flow/login')
        time.sleep(3)
        self.driver.find_element("xpath",
                                 "//*[@id=\"layers\"]/div/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div/div/div/div[5]/label/div/div[2]/div/input").send_keys(
            self.twi_username)
        time.sleep(3)
        self.driver.find_element("xpath",
                                 "//*[@id=\"layers\"]/div/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div/div/div/div[6]/div").click()
        time.sleep(2)
        self.driver.find_element("xpath",
                                 '//*[@id="layers"]/div/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div[1]/div/div[2]/label/div/div[2]/div/input').send_keys(
            self.twi_name)
        self.driver.find_element("xpath",
                                 "//*[@id=\"layers\"]/div/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div[2]/div/div/div/div/div").click()
        time.sleep(2)
        self.driver.find_element("xpath",
                                 "//*[@id=\"layers\"]/div/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div[1]/div/div/div[3]/div/label/div/div[2]/div[1]/input").send_keys(
            self.twi_password)
        self.driver.find_element("xpath",
                                 "//*[@id=\"layers\"]/div/div/div/div/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div[2]/div/div[1]/div/div/div").click()

        time.sleep(2)
        savedCookies = self.driver.get_cookies()
        for item in savedCookies:
            if item['name'] == 'ct0' or item['name'] == 'auth_token':
                self.cookies.update({item['name']: item['value']})

        self.headers = {
            'authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
            'x-csrf-token': self.cookies['ct0']
        }

    def get_request_headers(self):
        proxy = Proxy()
        proxy.proxy_type = ProxyType.MANUAL
        proxy.http_proxy = self.proxies['http']
        chrome_options = webdriver_.ChromeOptions()
        chrome_options.add_argument('--proxy-server=http://' + proxy.http_proxy)
        chrome_options.binary_location = self.chrome_binary_path
        driver = webdriver_.Chrome(executable_path=self.chrome_driver_path, chrome_options=chrome_options, seleniumwire_options={'proxy': proxy})
        driver.get('https://twitter.com/i/flow/login')
        for request in driver.requests:
            print('请求headers：')
            print(request.headers)
            break
        driver.quit()

    def req(self, url, params=None):
        response = requests.get(
            url,
            params=params,
            cookies=self.cookies,
            headers=self.headers,
            proxies=self.proxies
        )
        # if response.status_code != 200:
        #     raise Exception
        return response

    def get_id(self, screen_name):
        params = {
            'variables': '{"screen_name":"' + screen_name + '","withSafetyModeUserFields":true}',
            'features': '{"hidden_profile_likes_enabled":true,"hidden_profile_subscriptions_enabled":true,"rweb_tipjar_consumption_enabled":true,"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"subscriptions_verification_info_is_identity_verified_enabled":true,"subscriptions_verification_info_verified_since_enabled":true,"highlights_tweets_tab_ui_enabled":true,"responsive_web_twitter_article_notes_tab_enabled":true,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"responsive_web_graphql_timeline_navigation_enabled":true}',
        }
        res = self.req('https://twitter.com/i/api/graphql/qW5u-DAuXpMEG0zA1F7UGQ/UserByScreenName', params).json()
        res = res['data']['user']['result']
        return {'id': res['id'], 'rest_id': res['rest_id']}

    @staticmethod
    def parser_tweet_tag(content):
        item = content['data']['search_by_raw_query']['search_timeline']['timeline']['instructions'][0]['entries']
        '/data/search_by_raw_query/search_timeline/timeline/instructions/0/entries/1/content/itemContent/tweet_results/result/legacy/full_text'
        result = list()
        for i in item:
            if 'tweet' not in i['entryId']:
                continue
            result.append({
                'full_text': i['content']['itemContent']['tweet_results']['result']['legacy']['full_text'],
                'rest_id': i['content']['itemContent']['tweet_results']['result']['rest_id'],
                'user_id_str': i['content']['itemContent']['tweet_results']['result']['legacy']['user_id_str'],
                'created_at': i['content']['itemContent']['tweet_results']['result']['legacy']['created_at']
            })
        return result


    @staticmethod
    def parser_tweet(content):
        result = list()
        # result.append(res['data']['user']['result']['timeline_v2']['timeline']['instructions'][1])
        # result.extend(res['data']['user']['result']['timeline_v2']['timeline']['instructions'][2]['entries'])
        items = content['data']['user']['result']['timeline_v2']['timeline']['instructions']
        item = items[len(items) - 2]['entry']

        info = {
            'name':
                item['content']['itemContent']['tweet_results']['result']['core']['user_results']['result']['legacy'][
                    'name'],
            'brief':
                item['content']['itemContent']['tweet_results']['result']['core']['user_results']['result']['legacy'][
                    'description'],
            'Following':
                item['content']['itemContent']['tweet_results']['result']['core']['user_results']['result']['legacy'][
                    'friends_count'],
            'Followers':
                item['content']['itemContent']['tweet_results']['result']['core']['user_results']['result']['legacy'][
                    'followers_count'],
            'favourites':
                item['content']['itemContent']['tweet_results']['result']['core']['user_results']['result']['legacy'][
                    'favourites_count'],
        }
        result.append({
            'full_text': item['content']['itemContent']['tweet_results']['result']['legacy']['full_text'],
            'quoted_status_id_str': item['content']['itemContent']['tweet_results']['result']['legacy'][
                'quoted_status_id_str'],
            'id_str': item['content']['itemContent']['tweet_results']['result']['legacy']['id_str'],
            'created_at': item['content']['itemContent']['tweet_results']['result']['legacy']['created_at']
        })
        try:
            result[-1]['quoted_status_result'] = \
            item['content']['itemContent']['tweet_results']['result']['quoted_status_result']['result']['legacy'][
                'entities']['media']
        except Exception:
            result[-1]['quoted_status_result'] = None

        try:
            result[-1]['entities'] = item['content']['itemContent']['tweet_results']['result']['legacy']['entities'][
                'media']
        except Exception:
            result[-1]['entities'] = None

                                                                   # '/content/itemContent/tweet_results/result/quoted_status_result/result/legacy/entities/media/0/video_info/variants'
        # '/data/user/result/timeline_v2/timeline/instructions/1/entry/content/itemContent/tweet_results/result/legacy/entities/media'
        value = None
        for it in items[len(items) - 1]['entries']:
            if 'cursor-bottom' in it['entryId']:
                value = it['content']['value']
            if 'tweet' not in it['entryId']:
                continue
            result.append({
                'full_text': it['content']['itemContent']['tweet_results']['result']['legacy']['full_text'],
                'quoted_status_id_str': it['content']['itemContent']['tweet_results']['result']['legacy'].get(
                    'quoted_status_id_str'),
                'id_str': it['content']['itemContent']['tweet_results']['result']['legacy']['id_str'],
                'created_at': it['content']['itemContent']['tweet_results']['result']['legacy']['created_at'],
            })
            try:
                result[-1]['quoted_status_result'] = it['content']['itemContent']['tweet_results']['result']['quoted_status_result']['result']['legacy']['entities']['media']
            except Exception:
                result[-1]['quoted_status_result'] = None

            try:
                result[-1]['entities'] = it['content']['itemContent']['tweet_results']['result']['legacy']['entities']['media']
            except Exception:
                result[-1]['entities'] = None

        return result, info, value

    def get_content(self, id_, n):
        results, info, value = list(), dict(), None
        for _ in range(n):

            params = {
                'variables': '{"userId":"' + str(id_[
                                                     "rest_id"]) + '","count":20,"includePromotedContent":true,"withQuickPromoteEligibilityTweetFields":true,"withVoice":true,"withV2Timeline":true}',
                'features': '{"rweb_tipjar_consumption_enabled":true,"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"communities_web_enable_tweet_community_results_fetch":true,"c9s_tweet_anatomy_moderator_badge_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":true,"tweet_awards_web_tipping_enabled":false,"creator_subscriptions_quote_tweet_preview_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"rweb_video_timestamps_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_enhance_cards_enabled":false}',
                'fieldToggles': '{"withArticlePlainText":false}',
            }
            if value:
                params['variables'] = '{"userId":"' + str(id_[
                                                              "rest_id"]) + '","cursor":"' + value + '","count":20,"includePromotedContent":true,"withQuickPromoteEligibilityTweetFields":true,"withVoice":true,"withV2Timeline":true}'
            res = self.req('https://twitter.com/i/api/graphql/piUHOePH_uDdwbD9GkquJA/UserTweets', params)
            res = res.json()
            result, info, value = self.parser_tweet(res)
            results.extend(result)
        return results, info

    def get_Following(self, id_):
        params = {
            'variables': '{"userId":"' + str(id_[
                                                 "rest_id"]) + '","count":20,"includePromotedContent":false}',
            'features': '{"rweb_tipjar_consumption_enabled":true,"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"communities_web_enable_tweet_community_results_fetch":true,"c9s_tweet_anatomy_moderator_badge_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":true,"tweet_awards_web_tipping_enabled":false,"creator_subscriptions_quote_tweet_preview_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"rweb_video_timestamps_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_enhance_cards_enabled":false}',
        }
        res = self.req('https://twitter.com/i/api/graphql/-X4qqj9Rg1U-wAQPs8nj2g/Following', params).json()
        '/data/user/result/timeline/timeline/instructions/3/entries/0/content/itemContent/user_results/result/rest_id'
        result = list()
        for item in res['data']['user']['result']['timeline']['timeline']['instructions'][3]['entries']:
            if 'user' not in item['entryId']:
                continue
            result.append(item['content']['itemContent']['user_results']['result']['rest_id'])
        return result

    def get_Followers(self, id_):
        params = {
            'variables': '{"userId":"' + str(id_[
                                                 "rest_id"]) + '","count":20,"includePromotedContent":false}',
            'features': '{"rweb_tipjar_consumption_enabled":true,"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"communities_web_enable_tweet_community_results_fetch":true,"c9s_tweet_anatomy_moderator_badge_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":true,"tweet_awards_web_tipping_enabled":false,"creator_subscriptions_quote_tweet_preview_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"rweb_video_timestamps_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_enhance_cards_enabled":false}',
        }

        res = self.req('https://twitter.com/i/api/graphql/lvBeONlv8_bj7fByvLos9Q/BlueVerifiedFollowers', params).json()
        result = list()
        for item in res['data']['user']['result']['timeline']['timeline']['instructions'][3]['entries']:
            if 'user' not in item['entryId']:
                continue
            result.append(item['content']['itemContent']['user_results']['result']['rest_id'])
        return result

    def tweet_for_tag(self, tag):
        params = {
            'variables': '{"rawQuery":"' + tag + '","count":20,"querySource":"typed_query","product":"Top"}',
            'features': '{"rweb_tipjar_consumption_enabled":true,"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"communities_web_enable_tweet_community_results_fetch":true,"c9s_tweet_anatomy_moderator_badge_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":true,"tweet_awards_web_tipping_enabled":false,"creator_subscriptions_quote_tweet_preview_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"rweb_video_timestamps_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_enhance_cards_enabled":false}',
        }
        res = self.req('https://twitter.com/i/api/graphql/ncYrUaw-yLVgHbA9yXrj0A/SearchTimeline', params).json()
        result = self.parser_tweet_tag(res)
        return result

    def user_for_tag(self, tag):
        params = {
            'include_ext_is_blue_verified': '1',
            'include_ext_verified_type': '1',
            'include_ext_profile_image_shape': '1',
            'q': tag,
            'src': 'search_box',
            'result_type': 'events,users,topics,lists',
        }
        res = self.req('https://twitter.com/i/api/1.1/search/typeahead.json', params).json()
        result = list()
        for r in res['users']:
            result.append({
                'id_str': r['id_str'],
                'name': r['name'],
                'screen_name': r['screen_name'],
            })
        return result


if __name__ == '__main__':
    kwargs = {
        # 要爬取的推特用户名称
        'screen_name': ['catturd2'],
        # 要爬取的tag
        'tag': ['#AIProduct'],
        # 推特账号
        'twi_username': 'XXXXX@gmail.com',
        # 推特密码
        'twi_password': 'XXX.',
        # 推特名称
        'twi_name': 'XXXX',
        # 浏览器地址
        'chrome_binary_path': r"C:\Program Files (x86)\Chromebrowser\Chrome.exe",
        # 浏览器驱动地址
        'chrome_driver_path': r"C:\Users\25331\Downloads\chromedriver_win32\chromedriver.exe"
    }

    X = craw_X(**kwargs)
    X.run()
    # X.get_request_headers()
